//+------------------------------------------------------------------+
//|                                              ValidHighLowFinder.mq5 |
//|                        Copyright 2025, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

input int      MagicNumber = 88888;                // EA魔术棒
input int      LookbackBars = 500;                 // 分析的K线数量
input double   PointThreshold = 5000;              // 有效高低点阈值(点)

// 高线段参数
input double   HighSlopeStart = 6.0;               // 高线段第一阶段斜率起始值
input double   HighSlopeEnd = -6.0;                // 高线段第一阶段斜率终止值
input double   HighSlopeStep = 0.0005;              // 高线段斜率步长
input double   HighStandardThreshold = 5000;        // 高标准点阈值(点)
input color    HighLineColor1 = clrRed;             // 高线段颜色1
input color    HighLineColor2 = clrPink;            // 高线段颜色2
input int      HighLineWidth = 1;                  // 高线段宽度

// 低线段参数
input double   LowSlopeStart = -6.0;               // 低线段第一阶段斜率起始值
input double   LowSlopeEnd = 6.0;                  // 低线段第一阶段斜率终止值
input double   LowSlopeStep = 0.0005;               // 低线段斜率步长
input double   LowStandardThreshold = 5000;         // 低标准点阈值(点)
input color    LowLineColor1 = clrGreen;            // 低线段颜色1
input color    LowLineColor2 = clrYellow;           // 低线段颜色2
input int      LowLineWidth = 1;                   // 低线段宽度

// 结构体存储K线高低点信息
struct SBarInfo
{
   double   high;
   double   low;
   datetime time;
   int      index;
};

// 存储高低点信息
struct SValidPoints
{
   double   high;
   double   low;
   int      highIndex;
   int      lowIndex;
   datetime highTime;
   datetime lowTime;
} validPoints;

// 存储线段信息
struct SLineInfo
{
   double   slope;
   color    lineColor;
   string   lineName;
   datetime foundTime;
   double   foundPrice;
   int      stage;
};

SLineInfo lastHighLine, lastLowLine;

// 定义比较函数的类型
typedef int (*TCompareFunc)(const SBarInfo&, const SBarInfo&);

//+------------------------------------------------------------------+
//| 检查有效高点函数                                                  |
//+------------------------------------------------------------------+
bool IsValidHigh(const SBarInfo &bars[], int highIndex, int totalBars, double threshold)
{
   if(highIndex < 0 || highIndex >= totalBars) 
      return false;
      
   double highValue = bars[highIndex].high;
   bool leftFound = false;   // 向左（过去）找到低于高点的点
   bool rightFound = false;  // 向右（未来）找到低于高点的点
   
   // 向左检查（更早的K线，索引增加）
   for(int i = highIndex + 1; i < totalBars; i++)
   {
      if(bars[i].low < highValue - threshold)
      {
         leftFound = true;
         break;
      }
   }
   
   // 向右检查（更新的K线，索引减小）
   for(int i = highIndex - 1; i >= 0; i--)
   {
      if(bars[i].low < highValue - threshold)
      {
         rightFound = true;
         break;
      }
   }
   
   return (leftFound && rightFound);
}

//+------------------------------------------------------------------+
//| 检查有效低点函数                                                  |
//+------------------------------------------------------------------+
bool IsValidLow(const SBarInfo &bars[], int lowIndex, int totalBars, double threshold)
{
   if(lowIndex < 0 || lowIndex >= totalBars) 
      return false;
      
   double lowValue = bars[lowIndex].low;
   bool leftFound = false;   // 向左（过去）找到高于低点的点
   bool rightFound = false;  // 向右（未来）找到高于低点的点
   
   // 向左检查（更早的K线，索引增加）
   for(int i = lowIndex + 1; i < totalBars; i++)
   {
      if(bars[i].high > lowValue + threshold)
      {
         leftFound = true;
         break;
      }
   }
   
   // 向右检查（更新的K线，索引减小）
   for(int i = lowIndex - 1; i >= 0; i--)
   {
      if(bars[i].high > lowValue + threshold)
      {
         rightFound = true;
         break;
      }
   }
   
   return (leftFound && rightFound);
}

//+------------------------------------------------------------------+
//| 检查高标准点函数                                                  |
//+------------------------------------------------------------------+
bool IsValidHighStandard(const SBarInfo &bars[], int index, int totalBars, double threshold)
{
   if(index < 0 || index >= totalBars) 
      return false;
      
   double highValue = bars[index].high;
   bool leftFound = false;   // 向左（更早）找到低于高点的点
   bool rightFound = false;  // 向右（更新）找到低于高点的点
   
   // 向左检查（更早的K线，索引增加）
   for(int i = index + 1; i < totalBars; i++)
   {
      if(bars[i].low < highValue - threshold)
      {
         leftFound = true;
         break;
      }
   }
   
   // 向右检查（更新的K线，索引减小）
   for(int i = index - 1; i >= 0; i--)
   {
      if(bars[i].low < highValue - threshold)
      {
         rightFound = true;
         break;
      }
   }
   
   return (leftFound && rightFound);
}

//+------------------------------------------------------------------+
//| 检查低标准点函数                                                  |
//+------------------------------------------------------------------+
bool IsValidLowStandard(const SBarInfo &bars[], int index, int totalBars, double threshold)
{
   if(index < 0 || index >= totalBars) 
      return false;
      
   double lowValue = bars[index].low;
   bool leftFound = false;   // 向左（更早）找到高于低点的点
   bool rightFound = false;  // 向右（更新）找到高于低点的点
   
   // 向左检查（更早的K线，索引增加）
   for(int i = index + 1; i < totalBars; i++)
   {
      if(bars[i].high > lowValue + threshold)
      {
         leftFound = true;
         break;
      }
   }
   
   // 向右检查（更新的K线，索引减小）
   for(int i = index - 1; i >= 0; i--)
   {
      if(bars[i].high > lowValue + threshold)
      {
         rightFound = true;
         break;
      }
   }
   
   return (leftFound && rightFound);
}

//+------------------------------------------------------------------+
//| 按高点值降序排序的比较函数                                        |
//+------------------------------------------------------------------+
int CompareHigh(const SBarInfo &a, const SBarInfo &b)
{
   if(a.high < b.high) return 1;   // 降序排序
   if(a.high > b.high) return -1;
   return 0;
}

//+------------------------------------------------------------------+
//| 按低点值升序排序的比较函数                                        |
//+------------------------------------------------------------------+
int CompareLow(const SBarInfo &a, const SBarInfo &b)
{
   if(a.low > b.low) return 1;   // 升序排序
   if(a.low < b.low) return -1;
   return 0;
}

//+------------------------------------------------------------------+
//| 自定义数组排序函数                                                |
//+------------------------------------------------------------------+
void SortArray(SBarInfo &array[], int count, TCompareFunc compare)
{
   for(int i = 0; i < count - 1; i++)
   {
      for(int j = 0; j < count - i - 1; j++)
      {
         if(compare(array[j], array[j + 1]) > 0)
         {
            // 交换元素
            SBarInfo temp = array[j];
            array[j] = array[j + 1];
            array[j + 1] = temp;
         }
      }
   }
}

//+------------------------------------------------------------------+
//| 绘制趋势线                                                      |
//+------------------------------------------------------------------+
void DrawTrendLine(string name, datetime t1, double p1, datetime t2, double p2, color clr, int width, bool ray = false)
{
   if(ObjectFind(0, name) < 0)
   {
      ObjectCreate(0, name, OBJ_TREND, 0, t1, p1, t2, p2);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
      ObjectSetInteger(0, name, OBJPROP_RAY, ray);
      ObjectSetInteger(0, name, OBJPROP_BACK, true);
   }
   else
   {
      ObjectMove(0, name, 0, t1, p1);
      ObjectMove(0, name, 1, t2, p2);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   }
}

//+------------------------------------------------------------------+
//| 寻找高线段                                                       |
//+------------------------------------------------------------------+
void FindHighLine(const SBarInfo &bars[], int highIndex, double highPrice, int totalBars)
{
   double highThreshold = HighStandardThreshold * _Point;
   double tolerance = 10 * _Point; // 相交容差
   bool found = false;
   int foundIndex = -1;
   double foundSlope = 0;
   int stage = 0;
   datetime baseTime = bars[highIndex].time;

   // 第一阶段：斜率从大到小 (6.0 到 -6.0)
   for(double k = HighSlopeStart; k >= HighSlopeEnd; k -= HighSlopeStep)
   {
      found = false;
      // 检查右侧 (x>0)
      for(int i = highIndex - 1; i >= 0; i--) // 从基准点向右(新K线)
      {
         double x = highIndex - i; // x为正
         double y = k * x + highPrice;
         
         // 检查是否与K线相交
         if(y >= bars[i].low && y <= bars[i].high && 
            MathAbs(y - bars[i].high) <= tolerance)
         {
            if(IsValidHighStandard(bars, i, totalBars, highThreshold))
            {
               found = true;
               foundIndex = i;
               foundSlope = k;
               stage = 1;
               break;
            }
         }
      }
      if(found) break;
   }

   // 第二阶段：如果第一阶段未找到，斜率从小到大 (-6.0 到 6.0)
   if(!found)
   {
      for(double k = HighSlopeEnd; k <= HighSlopeStart; k += HighSlopeStep)
      {
         found = false;
         // 检查左侧 (x<0)
         for(int i = highIndex + 1; i < totalBars; i++) // 从基准点向左(老K线)
         {
            double x = highIndex - i; // x为负
            double y = k * x + highPrice;
            
            // 检查是否与K线相交
            if(y >= bars[i].low && y <= bars[i].high && 
               MathAbs(y - bars[i].high) <= tolerance)
            {
               if(IsValidHighStandard(bars, i, totalBars, highThreshold))
               {
                  found = true;
                  foundIndex = i;
                  foundSlope = k;
                  stage = 2;
                  break;
               }
            }
         }
         if(found) break;
      }
   }

   if(found)
   {
      // 计算当前K线位置的值
      double currentX = highIndex - 0; // 当前K线x值
      double currentY = foundSlope * currentX + highPrice;
      
      Print("高线段阶段", stage, "找到: 时间=", TimeToString(bars[foundIndex].time), 
            ", 斜率=", foundSlope, ", 最新K线值=", currentY);
      
      // 创建线段名称
      string lineName = "HighLine_" + IntegerToString(MagicNumber);
      
      // 确定线段颜色
      color lineColor;
      if(lastHighLine.slope == foundSlope && lastHighLine.lineName != "")
      {
         lineColor = lastHighLine.lineColor; // 斜率不变，使用原颜色
      }
      else
      {
         // 斜率变化，交替颜色
         if(lastHighLine.lineColor == HighLineColor1)
            lineColor = HighLineColor2;
         else
            lineColor = HighLineColor1;
      }
      
      // 绘制线段
      DrawTrendLine(lineName, baseTime, highPrice, bars[foundIndex].time, bars[foundIndex].high, 
                   lineColor, HighLineWidth);
      
      // 更新线段信息
      lastHighLine.slope = foundSlope;
      lastHighLine.lineColor = lineColor;
      lastHighLine.lineName = lineName;
      lastHighLine.foundTime = bars[foundIndex].time;
      lastHighLine.foundPrice = bars[foundIndex].high;
      lastHighLine.stage = stage;
   }
   else
   {
      Print("高线段未找到");
   }
}

//+------------------------------------------------------------------+
//| 寻找低线段                                                       |
//+------------------------------------------------------------------+
void FindLowLine(const SBarInfo &bars[], int lowIndex, double lowPrice, int totalBars)
{
   double lowThreshold = LowStandardThreshold * _Point;
   double tolerance = 10 * _Point; // 相交容差
   bool found = false;
   int foundIndex = -1;
   double foundSlope = 0;
   int stage = 0;
   datetime baseTime = bars[lowIndex].time;

   // 第一阶段：斜率从小到大 (-6.0 到 6.0)
   for(double k = LowSlopeStart; k <= LowSlopeEnd; k += LowSlopeStep)
   {
      found = false;
      // 检查右侧 (x>0)
      for(int i = lowIndex - 1; i >= 0; i--) // 从基准点向右(新K线)
      {
         double x = lowIndex - i; // x为正
         double y = k * x + lowPrice;
         
         // 检查是否与K线相交
         if(y >= bars[i].low && y <= bars[i].high && 
            MathAbs(y - bars[i].low) <= tolerance)
         {
            if(IsValidLowStandard(bars, i, totalBars, lowThreshold))
            {
               found = true;
               foundIndex = i;
               foundSlope = k;
               stage = 1;
               break;
            }
         }
      }
      if(found) break;
   }

   // 第二阶段：如果第一阶段未找到，斜率从大到小 (6.0 到 -6.0)
   if(!found)
   {
      for(double k = LowSlopeEnd; k >= LowSlopeStart; k -= LowSlopeStep)
      {
         found = false;
         // 检查左侧 (x<0)
         for(int i = lowIndex + 1; i < totalBars; i++) // 从基准点向左(老K线)
         {
            double x = lowIndex - i; // x为负
            double y = k * x + lowPrice;
            
            // 检查是否与K线相交
            if(y >= bars[i].low && y <= bars[i].high && 
               MathAbs(y - bars[i].low) <= tolerance)
            {
               if(IsValidLowStandard(bars, i, totalBars, lowThreshold))
               {
                  found = true;
                  foundIndex = i;
                  foundSlope = k;
                  stage = 2;
                  break;
               }
            }
         }
         if(found) break;
      }
   }

   if(found)
   {
      // 计算当前K线位置的值
      double currentX = lowIndex - 0; // 当前K线x值
      double currentY = foundSlope * currentX + lowPrice;
      
      Print("低线段阶段", stage, "找到: 时间=", TimeToString(bars[foundIndex].time), 
            ", 斜率=", foundSlope, ", 最新K线值=", currentY);
      
      // 创建线段名称
      string lineName = "LowLine_" + IntegerToString(MagicNumber);
      
      // 确定线段颜色
      color lineColor;
      if(lastLowLine.slope == foundSlope && lastLowLine.lineName != "")
      {
         lineColor = lastLowLine.lineColor; // 斜率不变，使用原颜色
      }
      else
      {
         // 斜率变化，交替颜色
         if(lastLowLine.lineColor == LowLineColor1)
            lineColor = LowLineColor2;
         else
            lineColor = LowLineColor1;
      }
      
      // 绘制线段
      DrawTrendLine(lineName, baseTime, lowPrice, bars[foundIndex].time, bars[foundIndex].low, 
                   lineColor, LowLineWidth);
      
      // 更新线段信息
      lastLowLine.slope = foundSlope;
      lastLowLine.lineColor = lineColor;
      lastLowLine.lineName = lineName;
      lastLowLine.foundTime = bars[foundIndex].time;
      lastLowLine.foundPrice = bars[foundIndex].low;
      lastLowLine.stage = stage;
   }
   else
   {
      Print("低线段未找到");
   }
}

//+------------------------------------------------------------------+
//| 主逻辑函数                                                        |
//+------------------------------------------------------------------+
void FindValidHighLow()
{
   // 只在每根K线开始时运行一次
   static datetime lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, _Period, 0);
   if(lastBarTime == currentBarTime) 
      return;
   lastBarTime = currentBarTime;
   
   // 获取品种和周期
   string symbol = _Symbol;
   ENUM_TIMEFRAMES period = _Period;
   
   // 计算实际点数阈值
   double threshold = PointThreshold * _Point;
   
   // 准备K线数据数组
   SBarInfo bars[];
   ArrayResize(bars, LookbackBars);
   
   // 填充K线数据（索引0为最新K线）
   for(int i = 0; i < LookbackBars; i++)
   {
      bars[i].high = iHigh(symbol, period, i);
      bars[i].low = iLow(symbol, period, i);
      bars[i].time = iTime(symbol, period, i);
      bars[i].index = i;  // 保存原始索引
   }
   
   // 创建用于排序的副本
   SBarInfo sortedBars[];
   ArrayResize(sortedBars, LookbackBars);
   ArrayCopy(sortedBars, bars);
   
   // 按高点降序排序
   SortArray(sortedBars, LookbackBars, CompareHigh);
   
   // 检查有效高点
   bool validHighFound = false;
   for(int i = 0; i < LookbackBars; i++)
   {
      int originalIndex = sortedBars[i].index;
      if(IsValidHigh(bars, originalIndex, LookbackBars, threshold))
      {
         validPoints.high = bars[originalIndex].high;
         validPoints.highIndex = originalIndex;
         validPoints.highTime = bars[originalIndex].time;
         Print("有效最高点: 时间=", TimeToString(bars[originalIndex].time), 
               ", 数值=", DoubleToString(bars[originalIndex].high, _Digits));
         validHighFound = true;
         break;
      }
   }
   if(!validHighFound)
      Print("有效最高点无");
   
   // 重置排序数组
   ArrayCopy(sortedBars, bars);
   
   // 按低点升序排序
   SortArray(sortedBars, LookbackBars, CompareLow);
   
   // 检查有效低点
   bool validLowFound = false;
   for(int i = 0; i < LookbackBars; i++)
   {
      int originalIndex = sortedBars[i].index;
      if(IsValidLow(bars, originalIndex, LookbackBars, threshold))
      {
         validPoints.low = bars[originalIndex].low;
         validPoints.lowIndex = originalIndex;
         validPoints.lowTime = bars[originalIndex].time;
         Print("有效最低点: 时间=", TimeToString(bars[originalIndex].time), 
               ", 数值=", DoubleToString(bars[originalIndex].low, _Digits));
         validLowFound = true;
         break;
      }
   }
   
   // 绘制高线段
   if(validHighFound)
   {
      FindHighLine(bars, validPoints.highIndex, validPoints.high, LookbackBars);
   }
   else
   {
      Print("有效最高点未找到");
   }
   
   // 绘制低线段
   if(validLowFound)
   {
      FindLowLine(bars, validPoints.lowIndex, validPoints.low, LookbackBars);
   }
   else
   {
      Print("有效最低点未找到");
   }
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   FindValidHighLow();
}
//+------------------------------------------------------------------+